package la.bbs558.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import la.bbs558.context.PointContext;
import la.bbs558.dao.BbsBoardDao;
import la.bbs558.dao.BbsPostDao;
import la.bbs558.dao.BbsReplyDao;
import la.bbs558.entity.*;
import la.bbs558.entity.vo.BbsReplyVO;
import la.bbs558.entity.enums.PointsOptType;
import la.bbs558.entity.enums.UserMessageType;
import la.bbs558.entity.enums.UserOpt;
import la.bbs558.exception.MsgException;
import la.bbs558.entity.params.*;
import la.bbs558.service.*;
import la.bbs558.util.Objs;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Optional;

/**
 * @author: Shanks
 * @date: 2023/12/15 22:43
 * @desc:
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class BbsReplyServiceImpl extends ServiceImpl<BbsReplyDao, BbsReply> implements BbsReplyService {

    private final BbsBoardDao bbsBoardDao;
    private final BbsPostDao bbsPostDao;
    private final BbsReplyDao bbsReplyDao;
    private final UserService userService;
    private final UserOptionService userOptionService;
    private final UserConfigService userConfigService;
    private final UserPointsLogService userPointsLogService;
    @Resource
    private UserDataService userDataService;
    @Resource
    private UserMessageService userMessageService;

    @Override
    public void listByPageForAdmin(ReplySearchPage searchPage) {
        getBaseMapper().selectByPageForAdmin(searchPage);
    }

    @Override
    public void postReplyList(BbsPostDetailPage page) {
        if(StpUtil.isLogin()){
            page.setUserId(StpUtil.getLoginIdAsLong());
        }
        getBaseMapper().replyList(page);
        List<BbsReplyVO> records = page.getRecords();
        for (BbsReplyVO record : records) {
            Long replyId = record.getReplyId();
            if (replyId != null) {
                BbsReplyVO bbsReply = bbsReplyDao.selectReplyById(replyId);
                record.setBbsReply(bbsReply);
            }
        }
    }

    @Override
    public void reply(BbsReplyParams params) {
        long userId = StpUtil.getLoginIdAsLong();
        Long postId = params.getPostId();
        Long replyId = params.getReplyId();
        if (Objs.isAllInvalid(postId, replyId)) {
            throw new MsgException("缺少必要参数");
        }
        BbsPost bbsPost = bbsPostDao.selectById(postId);
        if (bbsPost == null) {
            BbsReply bbsReply = bbsReplyDao.selectById(replyId);
            Objs.valid(bbsReply, "该回复已被删除");
            postId = bbsReply.getPostId();
            bbsPost = bbsPostDao.selectById(postId);
            Objs.valid(bbsPost, "该帖子已被删除");
        }
        Objs.isTrue(bbsPost.getState() == 1, "当前帖子正在审核中，无法回帖");
        String content = params.getContent();
        content = content.replaceAll("<[^>]*>", "");
//        Objs.isTrue(!SensitiveWordHelper.contains(content), "内容包含敏感词");
        // 更新最后回帖人信息
        new BbsPost()
                .setId(postId)
                .setLastTime(new Date())
                .setLastUser(userId)
                .updateById();
        // 新增回帖信息
        BbsReply bbsReply = new BbsReply()
                .setPostId(postId)
                .setReplyId(replyId)
                .setContent(content)
                .setMediaJson(params.getMediaJson())
                .setCreateUser(userId)
                .setFirst(0);
        bbsReply.insert();
        Long currentReplyId = bbsReply.getId();
        Long postCreateUser = bbsPost.getCreateUser();
        // 回复楼中楼
        if (Objs.isValid(replyId)) {
            // 更新回帖数
            getBaseMapper().updateReplyCnt(replyId);
            BbsReply reply = getById(replyId);
            Objs.valid(reply, "回复楼层已经不存在了");
            Objs.isTrue(reply.getState() == 1, "当前回复正在审核中，无法回复");
            Long replyCreateUser = reply.getCreateUser();
            // 回复楼中楼
            this.sendReplyMsg(replyCreateUser, userId, currentReplyId, postId);
            //如果回复人是楼主则只发一次
            if(!Objs.equal(postCreateUser,replyCreateUser)){
                // 回复楼主
                this.sendReplyMsg(postCreateUser, userId, currentReplyId, postId);
            }
        } else {
            // 更新回帖数
            bbsPostDao.updateReplyCnt(postId);
            // 回复楼主
            this.sendReplyMsg(postCreateUser, userId, currentReplyId, postId);
        }
        // 回复统计+1
        userDataService.lambdaUpdate().setSql("reply_cnt = reply_cnt + 1").eq(UserData::getUserId, userId).update();
        // 增加积分
        PointContext context = new PointContext(userId, currentReplyId, PointsOptType.REPLY, UserOpt.REPLY);
        userPointsLogService.getPoints(context);
        // @用户推送消息
        List<Long> atUserIds = params.getAtUsers();
        if (atUserIds == null) {
            return;
        }
        for (Long atUserId : atUserIds) {
            User atUser = userService.getById(atUserId);
            if (atUser == null) {
                continue;
            }
            // 回复@用户
            this.sendReplyMsg(atUserId, userId, currentReplyId, postId);
        }

    }

    @Override
    public void sendReplyMsg(Long toUser, Long fromUser, Long replyId, Long postId) {
        // 自己回复自己则不进行消息推送
        if(Objs.equals(toUser, fromUser)){
            return;
        }
        //是否开通消息通知
        UserConfig userConfig = userConfigService.initGetUserConfig(toUser);
        if (userConfig.getMessageConfig() != 1) {
            return;
        }
        //新增消息
        UserMessage userMessage = new UserMessage();
        userMessage.setUserId(toUser);
        userMessage.setMessageType(UserMessageType.MSG_RELAY.getCode());
        userMessage.setMsgContent("你有新的回复信息");
        userMessage.setState(0);
        userMessage.setReplyId(replyId);
        userMessage.setPostId(postId);
        userMessage.setFromUserId(fromUser);
        userMessage.insert();
        Integer count = userMessageService.lambdaQuery()
                .eq(UserMessage::getUserId, toUser)
                .eq(UserMessage::getState, 0)
                .count();
        //消息推送
        userMessageService.websocketUpdateMsgCount(toUser);
    }

    @Override
    public void listByUserId(UserCenterSearchPage<BbsReplyVO> searchPage) {
        getBaseMapper().selectListByUserId(searchPage);
        List<BbsReplyVO> records = searchPage.getRecords();
        records.forEach(bbsReplyVO -> {
            Long replyId = bbsReplyVO.getReplyId();
            if (replyId == null) {
                return;
            }
            BbsReplyVO reply = bbsReplyDao.selectReplyById(replyId);
            bbsReplyVO.setBbsReply(reply);
        });
    }

    @Override
    public void likeOrCollect(BbsOptParams params) {
        long userId = StpUtil.getLoginIdAsLong();
        Long replyId = params.getReplyId();
        Long postId = params.getPostId();
        //至少有一个不为空
        if (Objs.isAllValid(replyId, postId)) {
            throw new MsgException("缺少必要参数");
        }
        Integer type = params.getType();
        if(Objs.isInvalid(type) && type != 1 && type != 2){
            throw new MsgException("操作类型错误");
        }
        // 查询是否已点赞或收藏
        Optional<UserOption> userOption = userOptionService.lambdaQuery()
                .eq(UserOption::getUserId, userId)
                .eq(Objs.isValid(postId), UserOption::getPostId, postId)
                .eq(Objs.isValid(replyId), UserOption::getReplyId, replyId)
                .eq(UserOption::getType, type)
                .oneOpt();
        boolean isSure = !userOption.isPresent();
        BbsReplyDao bbsReplyDao = getBaseMapper();
        if (type == 1) {
            BbsReply bbsReply = getById(replyId);
            if (bbsReply == null) {
                throw new MsgException("回复楼层已经不存在了");
            }
            // 更新回帖
            int i = bbsReplyDao.likeForReply(replyId, type, isSure ? 1 : -1);
        } else if (type == 2) {
            BbsPost bbsPost = bbsPostDao.selectById(postId);
            if (bbsPost == null) {
                throw new MsgException("帖子已经不存在了");
            }
            // 更新帖子
            int i = bbsReplyDao.collectOrLikeForPost(postId, type, isSure ? 1 : -1);
        } else {
            throw new MsgException("参数错误");
        }

        if (isSure) {
            new UserOption()
                    .setUserId(userId)
                    .setPostId(postId)
                    .setReplyId(replyId)
                    .setType(type)
                    .insert();
            // 增加积分
            UserOpt userOpt;
            PointsOptType pointsOptType;
            Long optId = replyId == null ? postId : replyId;
            if (type != 1) {
                //收藏
                pointsOptType = PointsOptType.COLLECT;
                userOpt = replyId == null ? UserOpt.COLLECT_POST : UserOpt.COLLECT_REPLAY;
            } else {
                //点赞
                pointsOptType = PointsOptType.LIKE;
                userOpt = replyId == null ? UserOpt.LIKE_POST : UserOpt.LIKE_REPLAY;
            }
            PointContext context = new PointContext(userId, optId, pointsOptType, userOpt);
            userPointsLogService.getPoints(context);
            log.info("用户{} {} {}", userId, pointsOptType, optId);
        } else {
            //取消点赞或收藏
            Long id = userOption.get().getId();
            userOptionService.removeById(id);
            log.info("用户{}取消点赞或收藏了{}", userId, id);
        }
    }

    @Override
    public void postDetailLastPage(BbsPostDetailPage page) {
        // 创建一个分页查询对象，只查询总数，不查询数据
        page.setCurrent(1);
        getBaseMapper().replyList(page);
        page.setCurrent(page.getPages());
        postReplyList(page);
    }
}
